home *** CD-ROM | disk | FTP | other *** search
/ Aminet 4 / Aminet 4 - November 1994.iso / aminet / comm / net / dnet_src.lha / dnet / amiga / dnetdev / dnet.c next >
C/C++ Source or Header  |  1990-12-10  |  15KB  |  721 lines

  1. /*
  2.  *  DNET.C
  3.  *
  4.  *  DNet device dnet.device
  5.  *
  6.  *  Simulates a serial device using dnet.
  7.  *
  8.  *  This code is based on Matt Dillon's fms.device. (In fact whatever did not need
  9.  *  changing did not get changed).
  10.  *
  11.  *  Written by Karl R. Hakimian
  12.  *
  13.  *  Bugs & Limits
  14.  *  Only one read can be done at a time. A second read queued will abort the first
  15.  *    read.
  16.  *  SDCMD_BREAK, SDCMD_SETPARAMS are not supported.
  17.  *
  18.  *  Modification History
  19.  *  11-24-90 Karl Hakimian Original coding (hacking of fms.device)
  20.  *  12-02-90 Bug fixes support for SDCMD_QUERY added.
  21.  */
  22.  
  23. #include <exec/types.h>
  24. #include <exec/nodes.h>
  25. #include <exec/errors.h>
  26. #include <exec/memory.h>
  27. #include <exec/libraries.h>
  28. #include <devices/serial.h>
  29. #include <devices/timer.h>
  30. #include <libraries/dosextens.h>
  31.  
  32. /*#define DEBUG 1*/
  33.  
  34. #ifdef DEBUG
  35. int d_out;
  36. #endif
  37.  
  38. long DOSBase = NULL;
  39.  
  40. #define ABORTED (1<<5)
  41.  
  42. #define CMD_ABORTREQ    (0x7FF0)
  43. #define CMD_KILLPROC    (0x7FF1)
  44. #define CMD_STARTUP    (0x7FF1)
  45.  
  46. void CoProc();
  47.  
  48. extern int TagDevOpen();
  49. extern int TagDevClose();
  50. extern int TagDevExpunge();
  51. extern int TagDevBeginIO();
  52. extern int TagDevAbortIO();
  53.  
  54. extern void *CreateProc();
  55. extern void *CreatePort();
  56. extern void *AllocMem();
  57. extern void DUMmySeg();
  58.  
  59. typedef struct Library    LIB;
  60. typedef struct Device    DEV;
  61. typedef struct Process    PROC;
  62. typedef struct MsgPort    PORT;
  63. typedef struct Message    MSG;
  64. typedef struct List    LIST;
  65. typedef struct Node    NODE;
  66. typedef long (*func_ptr)();
  67.  
  68. typedef struct {
  69.     PORT    *Port;
  70. } NDUnit;
  71.  
  72. typedef struct {
  73.     LIB     Lib;
  74.     char    *Host;    /* NULL. I will do something with this when Matt does. */
  75.     int     Id;
  76. } NDev;
  77.  
  78. /* Taken from dnet:amiga/lib/dnetlib.h */
  79. typedef unsigned char   ubyte;
  80. typedef unsigned short  uword;
  81.  
  82. #define CHANN   struct _CHANN
  83.  
  84. CHANN {
  85.     PORT    port;       /*  receive data, replies       */
  86.     PORT    *dnetport;      /*  dnet's master port          */
  87.     LIST    rdylist;        /*  ready to be read        */
  88.     uword   chan;       /*  channel # for open channels */
  89.     ubyte   eof;        /*  channel remotely closed/eof */
  90.     ubyte   filler;
  91.     int     qlen;       /*  allowed write queue size    */
  92.     int     queued;     /*  current # packets queued    */
  93. };
  94.  
  95. #define DNCMD_WRITE 36  /*  Write data to a channel     */
  96.  
  97. typedef struct IOStdReq IOSTD;
  98. /* End of dnet stuff */
  99.  
  100. typedef struct IOExtSer IOB;
  101.  
  102. extern char DeviceName[];
  103. extern char IdString[];
  104.  
  105. long SysBase    = NULL;
  106. NDev *DevBase    = NULL;
  107. APTR DevSegment = NULL;
  108.  
  109. NDev *
  110. Init(seg)
  111. APTR seg;
  112. {
  113.     static func_ptr DevVectors[] = {
  114.     (func_ptr)TagDevOpen,
  115.     (func_ptr)TagDevClose,
  116.     (func_ptr)TagDevExpunge,
  117.     NULL,
  118.     (func_ptr)TagDevBeginIO,
  119.     (func_ptr)TagDevAbortIO,
  120.     (func_ptr)-1
  121.     };
  122.     NDev *db;
  123.  
  124.  
  125.     SysBase = *(long *)4;
  126.     DOSBase = OpenLibrary("dos.library",0);
  127.  
  128.     if (DOSBase == NULL)
  129.     return(NULL);
  130.  
  131.     DevBase = db = (NDev *)MakeLibrary((long **)DevVectors,NULL,NULL,sizeof(NDev),NULL);
  132.     db->Lib.lib_Node.ln_Type = NT_DEVICE;
  133.     db->Lib.lib_Node.ln_Name = DeviceName;
  134.     db->Lib.lib_Flags = LIBF_CHANGED|LIBF_SUMUSED;
  135.     db->Lib.lib_Version = 1;
  136.     db->Lib.lib_IdString= (APTR)IdString;
  137.     db->Host = NULL;
  138.     db->Id = 0;
  139.  
  140.     DevSegment = seg;
  141.     AddDevice((DEV *)db);
  142. #ifdef DEBUG
  143.     d_out = Open("con:0/0/320/200/Debug", 1006);
  144. #endif
  145.     return(db);
  146. }
  147.  
  148. NDev *
  149. DevOpen(unitnum, iob, flags)
  150. long unitnum;
  151. IOB  *iob;
  152. long flags;
  153. {
  154.     NDUnit *unit; 
  155.     IOB siob;
  156.     ULONG port;
  157.     char temp[32];
  158.     int id;
  159.     int i;
  160.  
  161. #ifdef DEBUG
  162.     Write(d_out,"Open\n",5);
  163. #endif
  164.     if ((unit = (NDUnit *)AllocMem(sizeof(NDUnit),MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
  165.     iob->IOSer.io_Error = IOERR_OPENFAIL;
  166.     iob->IOSer.io_Device = NULL;
  167.     return(DevBase);
  168.     }
  169.  
  170.     DevBase->Lib.lib_OpenCnt++;
  171.     id = DevBase->Id++;
  172. /*
  173.   Initialize CoProc process.
  174. */
  175.     sprintf(temp,"DNet %d",id);
  176.     port = (ULONG)CreateProc(temp, 0, (long)DUMmySeg >> 2, 4096);
  177.     sprintf(temp,"%x",port);
  178.  
  179.     if ((siob.IOSer.io_Message.mn_ReplyPort = CreatePort(NULL,0)) == NULL) {
  180.         DevBase->Lib.lib_OpenCnt--;
  181.         FreeMem(unit,sizeof(NDUnit));
  182.     iob->IOSer.io_Error = IOERR_OPENFAIL;
  183.     iob->IOSer.io_Device = NULL;
  184.         return(DevBase);
  185.     }
  186.  
  187.     siob.IOSer.io_Command = CMD_STARTUP;
  188.     siob.IOSer.io_Data = (APTR)unitnum;
  189.     siob.IOSer.io_Length = -1;
  190. /*
  191.   Lookup for childs port. Timeout in 10 seconds.
  192. */
  193.     for (i = 0; i < 10 && !(unit->Port = (PORT *)FindPort(temp)); i++)
  194.         Delay(50);
  195.  
  196.     if (unit->Port == NULL) {
  197.     iob->IOSer.io_Error = IOERR_OPENFAIL;
  198.     iob->IOSer.io_Device = NULL;
  199.         DevBase->Lib.lib_OpenCnt--;
  200.         FreeMem(unit,sizeof(NDUnit));
  201.     DeletePort(siob.IOSer.io_Message.mn_ReplyPort);
  202.     return(DevBase);
  203.     }
  204. /*
  205.   Send startup message.
  206. */
  207.     PutMsg(unit->Port,&siob.IOSer.io_Message);
  208.     WaitPort(siob.IOSer.io_Message.mn_ReplyPort);
  209.     (void)GetMsg(siob.IOSer.io_Message.mn_ReplyPort);
  210.     DeletePort(siob.IOSer.io_Message.mn_ReplyPort);
  211. /*
  212.   If there was an error on startup then quit.
  213. */
  214.     if (siob.IOSer.io_Error) {
  215.     DevBase->Lib.lib_OpenCnt--;
  216.     FreeMem(unit,sizeof(NDUnit));
  217.     iob->IOSer.io_Error = IOERR_OPENFAIL;
  218.     iob->IOSer.io_Device = NULL;
  219.     return(DevBase);
  220.     }
  221. /*
  222.   Initialize device and io request structure.
  223. */
  224.     DevBase->Lib.lib_Flags &= ~LIBF_DELEXP;
  225.     iob->IOSer.io_Unit = (struct NDUnit *)unit;
  226.     iob->IOSer.io_Error = 0;
  227.     return(DevBase);
  228. }
  229.  
  230. APTR
  231. DevExpunge()
  232. {
  233.  
  234.     if (DevSegment == NULL)
  235.     Alert(24, (char *)24);
  236.     if (DevBase->Lib.lib_OpenCnt) {
  237.     DevBase->Lib.lib_Flags |= LIBF_DELEXP;
  238.     return(NULL);
  239.     }
  240.     Remove((NODE *)DevBase);
  241.     CloseLibrary(DOSBase);
  242.     FreeMem((char *)DevBase - DevBase->Lib.lib_NegSize, DevBase->Lib.lib_NegSize + DevBase->Lib.lib_PosSize);
  243. #ifdef DEBUG
  244.     Close(d_out);
  245. #endif
  246.     return(DevSegment);
  247. }
  248.  
  249. APTR
  250. DevClose(iob)
  251. IOB *iob;
  252. {
  253.     IOB kiob;
  254.     NDUnit *unit;
  255.  
  256.     unit = (NDUnit *)iob->IOSer.io_Unit;
  257.  
  258.     if (unit == NULL  || DevBase->Lib.lib_OpenCnt == 0)
  259.         return(NULL);
  260. /*
  261.   Kill CoProc if it is still there.
  262. */
  263.     if (unit->Port) {
  264.     kiob.IOSer.io_Message.mn_ReplyPort = CreatePort(NULL, 0);
  265.     kiob.IOSer.io_Command = CMD_KILLPROC;
  266.     PutMsg(unit->Port, &kiob.IOSer.io_Message);
  267.     WaitPort(kiob.IOSer.io_Message.mn_ReplyPort);
  268.     DeletePort(kiob.IOSer.io_Message.mn_ReplyPort);
  269.     }
  270.  
  271.     FreeMem(unit,sizeof(NDUnit));
  272.  
  273.     if (DevBase->Lib.lib_OpenCnt && --DevBase->Lib.lib_OpenCnt)
  274.     return(NULL);
  275.  
  276.     if (DevBase->Lib.lib_Flags & LIBF_DELEXP)
  277.     return(DevExpunge());
  278.     /*
  279.      *    close down resources
  280.      */
  281.     return(NULL);
  282. }
  283.  
  284. void
  285. DevBeginIO(iob)
  286. IOB *iob;
  287. {
  288.     NDUnit *unit;
  289.     IOB *fiob;
  290.  
  291.     unit = (NDUnit *)iob->IOSer.io_Unit;
  292. #ifdef DEBUG
  293.     Write(d_out,"BeginIO\n",8);
  294. #endif
  295.     if (unit->Port == NULL) {
  296.     iob->IOSer.io_Error = SerErr_LineErr;
  297.     ReplyMsg(&iob->IOSer.io_Message);
  298.     return;
  299.     }
  300.  
  301.     iob->IOSer.io_Error = 0;
  302.     iob->IOSer.io_Actual = 0;
  303.  
  304.     switch(iob->IOSer.io_Command) {
  305.     case CMD_INVALID:
  306.     iob->IOSer.io_Error = IOERR_NOCMD;
  307.     break;
  308.     case CMD_RESET:
  309. #ifdef DEBUG
  310.     Write(d_out,"RESET\n",6);
  311. #endif
  312.     Forbid();
  313.  
  314.     while ((fiob = (IOB *)GetMsg(unit->Port))) {
  315.         fiob->IOSer.io_Flags |= ABORTED;
  316.         ReplyMsg(fiob);
  317.     }
  318.  
  319.     Permit();
  320.     PutMsg(unit->Port, &iob->IOSer.io_Message);
  321.     iob->IOSer.io_Flags &= ~IOF_QUICK;
  322.     iob = NULL;
  323.     break;
  324.     case CMD_READ:
  325. #ifdef DEBUG
  326.     Write(d_out,"READ\n",5);
  327. #endif
  328.     PutMsg(unit->Port, &iob->IOSer.io_Message);
  329.     iob->IOSer.io_Flags &= ~IOF_QUICK;    /*  not quick */
  330.     iob = NULL;
  331.     break;
  332.     case CMD_WRITE:
  333. #ifdef DEBUG
  334.     Write(d_out,"WRITE\n",6);
  335. #endif
  336.     PutMsg(unit->Port, &iob->IOSer.io_Message);
  337.     iob->IOSer.io_Flags &= ~IOF_QUICK;    /*  not quick */
  338.     iob = NULL;
  339.     break;
  340.     case CMD_CLEAR:
  341. #ifdef DEBUG
  342.     Write(d_out,"CLEAR\n",6);
  343. #endif
  344.     PutMsg(unit->Port, &iob->IOSer.io_Message);
  345.     iob->IOSer.io_Flags &= ~IOF_QUICK;
  346.     iob = NULL;
  347.     break;
  348.     case CMD_FLUSH:
  349. #ifdef DEBUG
  350.     Write(d_out,"FLUSH\n",6);
  351. #endif
  352.     Forbid();
  353.  
  354.     while ((fiob = (IOB *)GetMsg(unit->Port))) {
  355.         fiob->IOSer.io_Flags |= ABORTED;
  356.         ReplyMsg(fiob);
  357.     }
  358.  
  359.     Permit();
  360.     break;
  361.     case SDCMD_QUERY:
  362. #ifdef DEBUG
  363.     Write(d_out,"QUERY\n",6);
  364. #endif
  365.     PutMsg(unit->Port, &iob->IOSer.io_Message);
  366.     iob->IOSer.io_Flags &= ~IOF_QUICK;
  367.     iob = NULL;
  368.     break;
  369.     case CMD_STOP:
  370.     case CMD_START:
  371.     case SDCMD_SETPARAMS:
  372.     case SDCMD_BREAK:
  373. #ifdef DEBUG
  374.     Write(d_out,"OTHER\n",6);
  375. #endif
  376.     break;
  377.     default:
  378. #ifdef DEBUG
  379.     Write(d_out,"BAD\n",4);
  380. #endif
  381.     iob->IOSer.io_Error = IOERR_NOCMD;
  382.     break;
  383.     }
  384.     if (iob) {
  385.     if ((iob->IOSer.io_Flags & IOF_QUICK) == 0)
  386.         ReplyMsg((MSG *)iob);
  387.     }
  388.  
  389. }
  390.  
  391. DevAbortIO(iob)
  392. IOB *iob;
  393. {
  394.     IOB aiob;
  395.     IOB *riob;
  396.     NDUnit *unit; 
  397.     struct List *l;
  398.  
  399.     unit = (NDUnit *)iob->IOSer.io_Unit;
  400.  
  401.     if (unit->Port == NULL) {
  402.     iob->IOSer.io_Flags |= ABORTED;
  403.     ReplyMsg(iob);
  404.     return(IOERR_ABORTED);
  405.     }
  406.     
  407.     l = &unit->Port->mp_MsgList;
  408. /*
  409.   Search for the request in the message queue.
  410. */
  411. #ifdef DEBUG
  412.     Write(d_out,"AbortIO\n",8);
  413. #endif
  414.     Forbid();
  415.  
  416.     for (riob = (IOB *)l->lh_Head; riob; riob = (IOB *)(((struct Node *)riob)->ln_Succ)) {
  417. /*
  418.   Request found, remove it.
  419. */
  420.     if (riob == iob) {
  421.         Remove((struct Node *)riob);
  422.         iob->IOSer.io_Flags |= ABORTED;
  423.         break;
  424.     }
  425.  
  426.     }
  427.  
  428.     Permit();
  429. /*
  430.   If the request was not found, Tell CoProc to abort.
  431. */
  432.     if (!riob) {
  433.  
  434.     if ((aiob.IOSer.io_Message.mn_ReplyPort = CreatePort(NULL,0)) == NULL)
  435.         return(NULL);
  436.  
  437.     aiob.IOSer.io_Command = CMD_ABORTREQ;
  438.     aiob.IOSer.io_Data = (APTR)iob;
  439.     aiob.IOSer.io_Length = -1;
  440.     PutMsg(unit->Port, &aiob.IOSer.io_Message);
  441.     WaitPort(aiob.IOSer.io_Message.mn_ReplyPort);
  442.     DeletePort(aiob.IOSer.io_Message.mn_ReplyPort);
  443.     }
  444.     else
  445.     ReplyMsg(riob);
  446.  
  447.     if (iob->IOSer.io_Flags & ABORTED)
  448.     return(IOERR_ABORTED);
  449.  
  450.     return(0);
  451. }
  452.  
  453. /*
  454.  *    SERVER SIDE (IS A PROCESS)
  455.  */
  456.  
  457. void
  458. CoProc()
  459. {
  460.     IOB *iob;
  461.     IOSTD *dnreq;
  462.     NDUnit *unit;
  463.     PROC *proc;
  464.     PORT *port;
  465.     char notdone = 1;
  466.     int toread;
  467.     int haveread;
  468.     int read;
  469.     int data_ready = 0;
  470.     IOB *riob=NULL;
  471.     char pname[32];
  472.     int Chan;
  473.     int cmask;
  474.     int dmask;
  475.     int sig;
  476. #ifdef DEBUG
  477.     char buf[256];
  478. #endif
  479. /*
  480.   Create command message port.
  481. */
  482.     proc = (PROC *)FindTask(NULL);
  483.     sprintf(pname,"%x",&(proc->pr_MsgPort));
  484.  
  485.     if ((port = CreatePort(pname,0)) == NULL) {
  486.     return;
  487.     }
  488. /*
  489.   Wait for startup message.
  490. */
  491.     (void)Wait(1 << port->mp_SigBit);
  492.  
  493.     iob = (IOB *)GetMsg(port);
  494.  
  495.     if (iob->IOSer.io_Command != CMD_STARTUP || (Chan = DOpen(DevBase->Host,iob->IOSer.io_Data)) == NULL) {
  496.     iob->IOSer.io_Error = IOERR_OPENFAIL;
  497.         ReplyMsg(&iob->IOSer.io_Message);
  498.         DeletePort(port);
  499.         return;
  500.     }
  501.  
  502.     iob->IOSer.io_Error = 0;
  503.     ReplyMsg(&iob->IOSer.io_Message);
  504.  
  505.     DQueue(Chan,128);
  506.     dmask = 1 << ((PORT *)Chan)->mp_SigBit;
  507.     cmask = 1 << port->mp_SigBit;
  508. #ifdef DEBUG
  509.     sprintf(buf,"dmask = %xx, cmask = %xx\n",dmask,cmask);
  510.     Write(d_out,buf,strlen(buf));
  511. #endif
  512.  
  513.     while (notdone) {
  514.     sig = Wait(cmask|dmask);
  515.  
  516.     if (sig&cmask) {
  517.  
  518.         while (iob = (IOB *)GetMsg(port)) {
  519.         unit = (NDUnit *)iob->IOSer.io_Unit;
  520.  
  521.         switch(iob->IOSer.io_Command) {
  522.         case CMD_ABORTREQ:
  523. #ifdef DEBUG
  524.             Write(d_out,"ABORT\n",6);
  525. #endif
  526.  
  527.             if (iob->IOSer.io_Data == (APTR)riob) {
  528.             riob->IOSer.io_Flags |= ABORTED;
  529.             ReplyMsg(&riob->IOSer.io_Message);
  530.             riob = NULL;
  531.             }
  532.  
  533.             break;
  534.         case CMD_RESET:
  535. #ifdef DEBUG
  536.             Write(d_out,"RESET\n",6);
  537. #endif
  538.  
  539.             if (riob) {
  540.             riob->IOSer.io_Flags |= ABORTED;
  541.             ReplyMsg(&riob->IOSer.io_Message);
  542.             }
  543. /*
  544.   We want to fall through to clear.
  545. */
  546.         case CMD_CLEAR:
  547. #ifdef DEBUG
  548.             Write(d_out,"CLEAR\n",6);
  549. #endif
  550. /*
  551.   Remove all data from the read buffer.
  552. */
  553.             while (DNRead(Chan,(char *)&data_ready,1))
  554.             ;
  555.  
  556.             data_ready = 0;
  557.             break;
  558.         case SDCMD_QUERY:
  559. #ifdef DEBUG
  560.             Write(d_out,"QUERY\n",5);
  561. #endif
  562.             iob->io_Status = 0xf8;
  563.             Forbid();
  564.  
  565.             for (dnreq = (IOSTD *)((CHANN *)Chan)->rdylist.lh_Head; dnreq; dnreq = (IOSTD *)((struct Node *)dnreq)->ln_Succ) {
  566.  
  567.             if (dnreq->io_Command == DNCMD_WRITE)
  568.                 iob->IOSer.io_Actual += dnreq->io_Length - dnreq->io_Actual;
  569.  
  570.             }
  571.  
  572.             for (dnreq = (IOSTD *)((CHANN *)Chan)->port.mp_MsgList.lh_Head; dnreq; dnreq = (IOSTD *)((struct Node *)dnreq)->ln_Succ) {
  573.  
  574.             if (dnreq->io_Command == DNCMD_WRITE)
  575.                 iob->IOSer.io_Actual += dnreq->io_Length - dnreq->io_Actual;
  576.  
  577.             }
  578.  
  579.             Permit();
  580.             break;
  581.         case CMD_KILLPROC:
  582. #ifdef DEBUG
  583.             Write(d_out,"KILL\n",5);
  584. #endif
  585.             goto exit_proc;
  586.             break;
  587.         case CMD_READ:
  588. #ifdef DEBUG
  589.             Write(d_out,"READ\n",5);
  590. #endif
  591. /*
  592.   Currently only allows one read at a time. If a read request comes in while one
  593.   is still pending then abort the first read.
  594. */
  595.                 if (riob) {
  596.             riob->IOSer.io_Error = SerErr_LineErr;
  597.             ReplyMsg(&riob->IOSer.io_Message);
  598.             riob = NULL;
  599.             }
  600.  
  601.             toread = iob->IOSer.io_Length;
  602.             haveread = 0;
  603.             riob = iob;
  604.             iob = NULL;
  605.             break;
  606.         case CMD_WRITE:
  607. #ifdef DEBUG
  608.             Write(d_out,"WRITE\n",6);
  609. #endif
  610.  
  611.             if (iob->IOSer.io_Length >= 0)
  612.             iob->IOSer.io_Actual = DWrite(Chan, (char *)iob->IOSer.io_Data, iob->IOSer.io_Length);
  613.             else if (iob->IOSer.io_Length == -1)
  614.             iob->IOSer.io_Actual = DWrite(Chan, (char *)iob->IOSer.io_Data, strlen((char *)iob->IOSer.io_Data));
  615.             else
  616.             iob->IOSer.io_Actual = iob->IOSer.io_Length;
  617.  
  618.             if (iob->IOSer.io_Actual < 0) {
  619.             iob->IOSer.io_Error = SerErr_LineErr;
  620.             goto exit_proc;
  621.             }
  622.  
  623.             break;
  624.         default:
  625.             iob->IOSer.io_Error = SerErr_LineErr;
  626.             break;
  627.         }
  628.  
  629.         if (iob)
  630.             ReplyMsg(&iob->IOSer.io_Message);
  631.  
  632.         }
  633.  
  634.     }
  635. /*
  636.   Do the read if there is data and a pending read request.
  637. */
  638.     if (((sig&dmask) || data_ready) && riob) {
  639.  
  640.         if (toread == -1) {
  641.  
  642.         while (riob && (read = DNRead(Chan,(char *)&riob->IOSer.io_Data[haveread],1))) {
  643.             if ((char *)&riob->IOSer.io_Data[haveread] == '\0') {
  644.             riob->IOSer.io_Actual = haveread;
  645.             ReplyMsg(&riob->IOSer.io_Message);
  646.             riob = NULL;
  647.             toread = haveread = 0;
  648.             }
  649.  
  650.             haveread++;
  651.         }
  652.  
  653.         continue;
  654.         }
  655.  
  656.         read = DNRead(Chan, (char *)&riob->IOSer.io_Data[haveread], toread);
  657.  
  658.         if (read < 0) {
  659.         riob->IOSer.io_Error = SerErr_LineErr;
  660.         ReplyMsg(&riob->IOSer.io_Message);
  661.         iob = NULL;
  662.         goto exit_proc;
  663.         }
  664.         else if (read == 0)
  665.             data_ready = 0;
  666.         else {
  667.         data_ready = 1;    /* data_read is true until no data is left. */
  668.         haveread += read;
  669.         toread -= haveread;
  670.         }
  671.  
  672.         if (toread <= 0) {
  673.         riob->IOSer.io_Actual = haveread;
  674.         ReplyMsg(&riob->IOSer.io_Message);
  675.         riob = NULL;
  676.         toread = haveread = 0;
  677.         }
  678.  
  679.     }
  680.     else if (sig&dmask)    /* There is data ready so record rember it. */
  681.         data_ready = 1;
  682.  
  683.     }
  684.     /* fall through to exit */
  685.  
  686.     Forbid();        /*  Forbid before exiting. */
  687.     return;
  688.  
  689. exit_proc:
  690. #ifdef DEBUG
  691.     Write(d_out,"exiting\n",8);
  692. #endif
  693.  
  694.     if (riob) {
  695.     riob->IOSer.io_Error = SerErr_LineErr;
  696.     ReplyMsg(&riob->IOSer.io_Message);
  697.     }
  698.  
  699.     DClose(Chan);
  700. #ifdef DEBUG
  701.     Write(d_out,"DNET closed\n",12);
  702. #endif
  703.  
  704.     while (riob = (IOB *)GetMsg(port)) {
  705.     riob->IOSer.io_Error = SerErr_LineErr;
  706.     riob->IOSer.io_Flags |= ABORTED;
  707.     ReplyMsg(&riob->IOSer.io_Message);
  708.     }
  709.  
  710.     DeletePort(port);
  711.     unit->Port = NULL;
  712. #ifdef DEBUG
  713.     Write(d_out,"Port gone\n",10);
  714. #endif
  715.     Forbid();        /*  Forbid before exiting. */
  716.  
  717.     if (iob)
  718.     ReplyMsg(&iob->IOSer.io_Message);
  719.  
  720. }
  721.